Skip to content

feat(commands): establish Telegram projection contract - #97169

Closed
andrexibiza wants to merge 1 commit into
NousResearch:mainfrom
andrexibiza:commands/pr8-telegram-projection
Closed

andrexibiza wants to merge 1 commit into
NousResearch:mainfrom
andrexibiza:commands/pr8-telegram-projection

Conversation

@andrexibiza

@andrexibiza andrexibiza commented Aug 28, 2026 •

Copy link
Copy Markdown

What does this PR do?

PR8 establishes the Telegram projection boundary for the unified slash-command architecture in #96692.

Telegram currently has three platform-specific concerns that must not become a second command authority:

  1. the Bot API exposes a bounded native command menu with stricter naming rules than Hermes command identity;
  2. Telegram may deliver /command@bot args, while the command plane must authorize and execute the same canonical command as /command args;
  3. native command registration is remote state, so a successful write is not sufficient proof that the intended menu actually settled.

This PR isolates those concerns behind three bounded modules. The canonical command catalog remains the semantic authority; Telegram receives an immutable projection of that catalog, normalizes Telegram-specific syntax back to canonical identity, and reconciles native menu state with exact ordered read-back before settlement.

The approach is intentionally dependency-light and independently landable. Current main does not yet expose the merged PR1/PR2 catalog/dispatcher ABIs, so PR8 consumes the catalog object/JSON shape without defining a competing schema or invocation/result contract. When #97143 and #97153 land, the Telegram adapter can compose this seam directly rather than absorbing more command semantics into the existing adapter.

Invariants

  • One semantic authority: Telegram projects catalog state; it does not define command identity or execution semantics.
  • Stable identity survives projection: non-blank command_id is authoritative; canonical name is the explicit current-v1 compatibility fallback.
  • Native omission is not semantic omission: commands excluded by Telegram's native limits or native-name rules remain resolvable through typed command input.
  • Addressing is syntax, not identity: /command@HermesBot args and /command args settle to the same canonical command when the bot target matches.
  • Unknown slash-shaped input does not become prompt text: command attempts remain typed unknown/invalid outcomes rather than silently crossing into model input.
  • Collisions fail closed: duplicate stable IDs, typed tokens, aliases, or sanitized native names cannot select authority by incidental catalog order.
  • Remote mutation requires proof: reconciliation advances state only after the exact ordered native payload is observed after a write.
  • Scope is part of settlement: a receipt from one Telegram command scope cannot authorize NOOP in another.

Deliberate non-goals

  • No edits to plugins/platforms/telegram/adapter.py in this slice.
  • No edits to hermes_cli/commands.py.
  • No duplicate CommandCatalog, CommandInvocation, or CommandResult ABI.
  • No behavior change at production call sites until the catalog/dispatcher slices land and the adapter composes this seam.
  • No expansion of an existing godfile; all six added files remain well below the 2,000-line ceiling.

Related Issue

Part of #96692 — this PR is PR8 of the unified slash-command decomposition and must not close the parent architecture issue by itself.

Interlocks:

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 🔒 Security fix
  • 📝 Documentation update
  • ✅ Tests (adding or improving test coverage)
  • ♻️ Refactor (no behavior change)
  • 🎯 New skill (bundled or hub)

Changes Made

  • hermes_cli/telegram_command_projection.py
    • Adds an immutable Telegram projection over one exact catalog snapshot.
    • Preserves catalog order while separating typed bindings from the bounded native Bot API payload.
    • Produces explicit HIDDEN, NATIVE_NAME_INVALID, and NATIVE_LIMIT omissions.
    • Sanitizes native Telegram names without weakening canonical typed resolution.
    • Rejects duplicate stable identities, typed-token collisions, and sanitized native-name collisions.
    • Carries catalog revision plus a deterministic projection fingerprint.
  • hermes_cli/telegram_command_normalization.py
    • Classifies Telegram text into typed NOT_COMMAND, KNOWN_COMMAND, UNKNOWN_COMMAND, NOT_FOR_THIS_BOT, and INVALID_COMMAND outcomes.
    • Normalizes /command@bot args and /command args to the same canonical command identity for the addressed bot.
    • Preserves raw arguments while producing canonical dispatcher input.
    • Keeps slash-prefixed paths/code out of command handling and prevents unknown command attempts from falling through as ordinary prompt text.
  • hermes_cli/telegram_menu_reconciliation.py
    • Adds deterministic NOOP, ADOPT, and SET planning for one Telegram command scope.
    • Detects catalog revision changes and remote drift.
    • Requires post-write read-back for SET plans.
    • Produces a settlement only when the observed ordered payload exactly matches the desired projection.
    • Rejects cross-scope settlement reuse.
  • tests/hermes_cli/test_telegram_command_projection.py
    • Characterizes stable IDs, PR1-shaped catalog compatibility, order, visibility, aliases, sanitization, native limits, immutability, and collision refusal.
  • tests/hermes_cli/test_telegram_command_normalization.py
    • Characterizes addressed/unaddressed equivalence, foreign-bot refusal, unknown command typing, path/code non-command classification, and typed fallback for native-menu omissions.
  • tests/hermes_cli/test_telegram_menu_reconciliation.py
    • Characterizes adoption, no-op, remote drift, revision change, exact read-back settlement, and scope isolation.

Exact object and footprint

  • Base: 9978706e9303dbf990d90e744b131361449d73b9
  • Head: 83f67367f80bcd48aaa734fbb14907f8954b3f85
  • Tree: 7188455480e071a0aafd3d6b5e87b7cf40915937
  • Commit topology: 1 commit, 1 ahead / 0 behind the pinned base
  • Diff: 6 added files, 1,426 additions, 0 deletions
  • Largest changed file: 527 lines
  • Existing godfiles modified: 0
  • Live code + open-PR FILE-LIST scan: no competing owner found for these six paths

Exact blob identities:

Path Blob SHA
hermes_cli/telegram_command_projection.py 897ff75623b2b99a1e7dc0c29512e1d9562e9c1a
hermes_cli/telegram_command_normalization.py 8b3616e9a3893613a197ad59f811e7177db47fca
hermes_cli/telegram_menu_reconciliation.py b3af37d4c709c6261c1be9eb3fe84d4ddcb0632f
tests/hermes_cli/test_telegram_command_projection.py 4cffb4e17f29a4741733d166ce4e800803ad39e3
tests/hermes_cli/test_telegram_command_normalization.py 0dae01a42f52f528e1a804a524df4ede3ca2a855
tests/hermes_cli/test_telegram_menu_reconciliation.py 0440522406fef959e175a88e57db496e3f0a7aad

How to Test

  1. Run the focused PR8 characterization suite:

    PYTHONPATH=. pytest -q \
      tests/hermes_cli/test_telegram_command_projection.py \
      tests/hermes_cli/test_telegram_command_normalization.py \
      tests/hermes_cli/test_telegram_menu_reconciliation.py

    Expected receipt: 26 passed.

  2. Run repository Python validation against the exact head. Hosted CI already executed the full Python test matrix, E2E suite, Ruff enforcement, Ruff + ty differential, Windows footgun gate, macOS-only tests, Windows-only tests, supply-chain checks, attribution checks, and common-ancestor checks successfully.

  3. Verify exact-head packaging/system acceptance:

  4. Characterization points worth checking explicitly:

    • /status@HermesBot Mixed CASE --Flag and /status Mixed CASE --Flag produce the same command identity and canonical input.
    • A command omitted from the native menu because of the Bot API command limit remains a typed known command.
    • foo-bar / foo_bar native-name collisions fail closed instead of depending on catalog order.
    • A successful native-menu write without exact read-back cannot produce a settlement.
    • A settlement for one scope cannot authorize NOOP in another scope.

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/ -q and all tests pass
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: GitHub-hosted Linux, macOS, and Windows; Docker amd64/arm64; Nix flake acceptance

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — or N/A — N/A: behavior is defined by bounded module docstrings and characterization tests; no user-facing command behavior is wired in this slice
  • I've updated cli-config.yaml.example if I added/changed config keys — or N/A — N/A: no configuration keys added or changed
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — or N/A — N/A: no contributor workflow or repository instruction contract changed
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — or N/A — exact-head Windows and macOS jobs are green; logic is platform-independent
  • I've updated tool descriptions/schemas if I changed tool behavior — or N/A — N/A: no tool schema or tool behavior changed

Screenshots / Logs

No UI surface is changed in PR8, so screenshots are not applicable.

Focused characterization receipt:

PYTHONPATH=. pytest -q \
  tests/hermes_cli/test_telegram_command_projection.py \
  tests/hermes_cli/test_telegram_command_normalization.py \
  tests/hermes_cli/test_telegram_menu_reconciliation.py

26 passed

Hosted acceptance for the exact submitted head 83f67367f80bcd48aaa734fbb14907f8954b3f85:

Acceptance authority Result Receipt
Repository CI ✅ Success run 33174052138
Docker amd64 + arm64 ✅ Success run 33174051342
Nix flake check ✅ Success run 33174051419

Every commit in the submitted PR topology is green.

@alt-glitch alt-glitch added type/feature New feature or request comp/cli CLI entry point, hermes_cli/, setup wizard platform/telegram Telegram bot adapter P3 Low — cosmetic, nice to have labels Aug 28, 2026
@andrexibiza
andrexibiza force-pushed the commands/pr8-telegram-projection branch from c209d9c to 83f6736 Compare August 28, 2026 13:42
@Enough1122

Copy link
Copy Markdown

AI code review — automated review for reference; please use your judgment.

Overall: Establishes Telegram projection contract (PR-8 under #96692) — deterministic, revision-aware, test-heavy.

What it does

  • New hermes_cli/telegram_command_projection.py (527 lines) builds an immutable Telegram menu projection from a catalog snapshot: name sanitization, native visibility, native limits (TELEGRAM_BOT_API_MAX_COMMANDS), fingerprint.
  • New hermes_cli/telegram_command_normalization.py (141 lines) normalizes /command@bot with TelegramCommandAttemptStatus vs catalog/dispatcher identity.
  • New hermes_cli/telegram_menu_reconciliation.py (195 lines) does revision-aware native-menu reconciliation + exact settlement (TelegramMenuReconciliationAction, Settlement, VerificationStatus).
  • Tests test_telegram_command_projection, test_telegram_command_normalization, test_telegram_menu_reconciliation pin sanitization, limits, fingerprint determinism, and settlement.

Non-blocking notes

  • _TELEGRAM_INVOCATION_RE allows A-Za-z0-9_- after first char — verify bot username handling doesn't accept trailing _/- which Telegram rejects; regex is permissive but projection sanitization may later reject, so double-check error path is user-visible.
  • Projection is purely deterministic fingerprint — if catalog ordering changes, fingerprint changes and triggers reconciliation; that's intended, but ensure catalog snapshot ordering is stable (sorted by command_id) to avoid spurious menu updates.

No runtime wiring in this PR (bounded seam only) — correct narrow-waist approach.

Non-blocking — please use your judgment.

Copy link
Copy Markdown
Author

Producer exact-object closure receipt for PR8 (no self-review).

Re-verified live on exact submitted head 83f67367f80bcd48aaa734fbb14907f8954b3f85: one surviving commit, 6 added files, PR open/non-draft/mergeable. The latest hosted acceptance is fully green on that exact object: CI 33176653845 ✅, Docker 33176653106 ✅, Nix 33176653073 ✅. These newer successful runs supersede the older green run IDs recorded in the PR body; they do not change the submitted object.

Landing-edge cross-check: live main@e60983a69730c058ce772829df3273aee6de3889 is 79 commits beyond the PR8 construction pin 9978706e9303dbf990d90e744b131361449d73b9. The compare interval contains none of PR8's six paths (hermes_cli/telegram_command_projection.py, hermes_cli/telegram_command_normalization.py, hermes_cli/telegram_menu_reconciliation.py, or the three corresponding characterization tests), so there is no current file-level landing collision on this slice.

Every surviving PR commit is therefore hosted-green and the producer-side execution/landing-edge gate is current. I am not submitting a review on my own code; independent acceptance remains separate from this producer receipt.

@andrexibiza

Copy link
Copy Markdown
Author

Closed as part of the volume narrowing of October 2 for possible later reprioritization. This closure is not a statement on the merits.

With the maintainers limiting external contributors to three open PRs, I'm narrowing my queue to the current top priorities. The feature is scoped and tested; it reopens when there's review bandwidth for it. The branch, commits, and discussion here stay intact, and I intend to reopen this when a slot frees.

@andrexibiza andrexibiza closed this Oct 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cli CLI entry point, hermes_cli/, setup wizard P3 Low — cosmetic, nice to have platform/telegram Telegram bot adapter type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants